<?php
namespace app\services;

use app\services\BaseServices;
use think\facade\Config;
use Redis;
use Exception;
use think\facade\Env;

class RedisService 
{
    private static $instance = null;
    private $redis;

    // 构造函数私有化，防止直接创建实例
    private function __construct()
    {
        $this->redis = new \Redis();

        // 获取 Redis 配置，可以在 config/redis.php 中定义 Redis 配置项
        $config = Config::get('cache.redis');
        try {
            
            $this->redis->connect(Env::get('REDIS.REDIS_HOSTNAME', '127.0.0.1'), Env::get('REDIS.PORT', '6379'), '60');
            if (!empty(Env::get('REDIS.REDIS_PASSWORD', ''))) {
                $this->redis->auth($config['password']);
            }
            if (!empty(Env::get('REDIS.REDIS_PASSWORD', ''))) {
                $this->redis->select(Env::get('REDIS.SELECT', ''));
            }
        } catch (Exception $e) {
            throw new Exception("Redis 连接失败: " . $e->getMessage());
        }
    }

    // 获取 RedisService 实例
    public static function getInstance()
    {
        if (self::$instance === null) {
            self::$instance = new self();
        }
        return self::$instance;
    }

    // 禁止克隆实例
    private function __clone() {}

    // 获取 Redis 实例
    public function getRedis()
    {
        return $this->redis;
    }

    // 示例方法：设置键值
    public function set($key, $value, $expire = 0)
    {
        $this->redis->set($key, $value);
        if ($expire > 0) {
            $this->redis->expire($key, $expire);
        }
    }

    public function  exists($key){
        return $this->redis->get($key) ? true : false;
    }

    // 示例方法：获取键值
    public function get($key)
    {
        return $this->redis->get($key);
    }

    // 如果键不存在则设置键值
    public function setnx($key, $value)
    {
        return $this->redis->setnx($key, $value);
    }

    // List 操作：向左边推入列表
    public function lPush($key, $value)
    {
        return $this->redis->lPush($key, $value);
    }

    // List 操作：向右边推入列表
    public function rPush($key, $value)
    {
        return $this->redis->rPush($key, $value);
    }

    // List 操作：从左边弹出一个元素
    public function lPop($key)
    {
        return $this->redis->lPop($key);
    }

    // List 操作：从右边弹出一个元素
    public function rPop($key)
    {
        return $this->redis->rPop($key);
    }

    // List 操作：获取列表长度
    public function lLen($key)
    {
        return $this->redis->lLen($key);
    }



    // List 操作：获取列表中指定范围的元素
    public function lRange($key, $start, $stop)
    {
        return $this->redis->lRange($key, $start, $stop);
    }

    public function delete($key)
    {
        return $this->redis->del($key);
    }

        /**
     * Redis 锁机制
     * @param string $lock 锁的键名
     * @param mixed $param 传入的参数，用于回调函数
     * @param Closure $func 执行的回调函数
     * @param int $ttl 锁的有效期，单位为秒
     * @return mixed 回调函数的执行结果
     * @throws Exception
     */
    public function lock($lock, $param, \Closure $func, $ttl = 3)
    {
        // 尝试获取锁
        $isLocked = $this->redis->setnx($lock, 1);

        if (!$isLocked) {
            throw new \Exception('请求过快，请稍后再试哦~');
        }

        // 设置锁的过期时间，防止死锁
        $this->redis->expire($lock, $ttl);

        try {
            // 执行回调函数并传入参数和 Redis 实例
            $result = $func($param, $this->redis);
        } finally {
            // 释放锁，确保在回调执行完后删除锁
            $this->redis->del($lock);
        }

        return $result;
    }
}
